iT邦幫忙

2024 iThome 鐵人賽

DAY 6
0
佛心分享-SideProject30

收納規劃APP系列 第 6

Day6:ngx-moveable 變形功能之三角形處理 (同場加映Canvas)

  • 分享至 

  • xImage
  •  

寫到一半,突然意識到有角架、角櫃的存在,所以開始跟三角形搏鬥
希望可以藉由點擊頂點來改變三角形的形狀,但是 ngx-movable 跟我理想的情況有點差距,所以寫了一下 canvas 的作法,用的原理是我唯一會的三角形公式:A平方=B平方+C平方,來計算邊長

做是做出來了,但還要再做拖曳跟轉圈,頓時覺得有點麻煩,還要處理矩形跟圓形,只有30天估計是不夠,除了時間之外還要考慮精神跟心理壓力,卡關卡太久很消耗意志力肌肉,所以又回去找套件

兜兜轉轉最後又回去使用 ngx-moveable,先用裡面的 warpable 將就使用一下,雖然沒有到 canvas一樣那麼直觀,但可以達到一樣效果。

以下提供 ngx-moveable 跟同場加映的 canvas 。
另外也把圖形們做成 ngx-moveable 的元件
詳細程式碼以及如何把圖形拆成元件的請看 Stackblitz 的 Day6,裡面所使用的功能可以到 feature 資料夾看。


ngx-moveable

triangle.component.ts

import { Component, ElementRef, ViewChild } from '@angular/core';
import { NgxMoveableComponent } from 'ngx-moveable';

@Component({
  selector: 'app-triangle',
  templateUrl: './triangle.component.html',
  styleUrl: './triangle.component.scss',
})
export class TriangleComponent {
  @ViewChild('moveableRef') moveableRef!: NgxMoveableComponent;

  @ViewChild('triangleRef') triangleRef!: ElementRef<HTMLDivElement>;
  draggable: any = true;
  throttleDrag: any = 1;
  edgeDraggable: any = false;
  startDragRotate: any = 0;
  throttleDragRotate: any = 0;
  warpable: any = true;
  rotatable: any = true;
  throttleRotate: any = 0;
  rotationPosition: any = 'top';
  renderDirections: any = ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se'];

  onWarp(event: any) {
    event.target.style.transform = event.transform;
  }
  onDrag(e: { target: { style: { transform: any } }; transform: any }) {
    e.target.style.transform = e.transform;
  }

  onRotate(e: {
    target: { style: { transform: any } };
    drag: { transform: any };
  }) {
    e.target.style.transform = e.drag.transform;
  }
}

triangle.component.html

<div class="triangle" #triangleRef>安勾</div>
<ngx-moveable
  [target]="triangleRef"
  [warpable]="warpable"
  [renderDirections]="renderDirections"
  (warp)="onWarp($event)"
  [draggable]="draggable"
  [throttleDrag]="throttleDrag"
  [edgeDraggable]="edgeDraggable"
  [startDragRotate]="startDragRotate"
  [throttleDragRotate]="throttleDragRotate"
  [rotatable]="rotatable"
  [throttleRotate]="throttleRotate"
  [rotationPosition]="rotationPosition"
  (rotate)="onRotate($event)"
  (drag)="onDrag($event)"
></ngx-moveable>

triangle.component.scss

.triangle {
  width: 0;
  height: 0;
  // border-left: 50px solid transparent;
  border-right: 100px solid transparent;
  border-bottom: 200px solid #007bff;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  position: absolute;
  color: white;
  top: 150px;
  left: 200px;
}

Canvas

triangle-canvas.component.html

<canvas id="myCanvas" width="500" height="500"></canvas>

triangle-canvas.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-triangle-canvas',
  templateUrl: './triangle-canvas.component.html',
  styleUrl: './triangle-canvas.component.scss',
})
export class TriangleCanvasComponent {
  private canvas: HTMLCanvasElement | undefined;
  private context: CanvasRenderingContext2D | undefined;
  private points = [
    { x: 50, y: 50 },
    { x: 150, y: 50 },
    { x: 100, y: 150 },
  ];
  private draggingPoint: any = null;

  ngAfterViewInit() {
    this.canvas = document.getElementById('myCanvas') as HTMLCanvasElement;
    this.context = this.canvas.getContext('2d')!;
    this.drawTriangle();

    this.canvas.addEventListener('mousedown', this.onMouseDown.bind(this));
    this.canvas.addEventListener('mousemove', this.onMouseMove.bind(this));
    this.canvas.addEventListener('mouseup', this.onMouseUp.bind(this));
  }

  private drawTriangle() {
    if (this.context && this.canvas) {
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      this.context.beginPath();
      this.context.moveTo(this.points[0].x, this.points[0].y);
      this.context.lineTo(this.points[1].x, this.points[1].y);
      this.context.lineTo(this.points[2].x, this.points[2].y);
      this.context.closePath();
      this.context.strokeStyle = 'black';
      this.context.stroke();

      this.context.fillStyle = 'rgba(255, 204, 255)';
      this.context.fill();
    }
  }

  private onMouseDown(event: MouseEvent) {
    if (this.canvas) {
      const rect = this.canvas.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      this.points.forEach((point) => {
        const distance = Math.sqrt((x - point.x) ** 2 + (y - point.y) ** 2);
        if (distance < 10) {
          this.draggingPoint = point;
        }
      });
    }
  }

  private onMouseMove(event: MouseEvent) {
    if (this.draggingPoint && this.canvas) {
      const rect = this.canvas.getBoundingClientRect();
      this.draggingPoint.x = event.clientX - rect.left;
      this.draggingPoint.y = event.clientY - rect.top;
      this.drawTriangle();
    }
  }

  private onMouseUp() {
    this.draggingPoint = null;
  }
}


上一篇
Day5:ngx-moveable 實作拖曳、縮放、旋轉功能
下一篇
Day7:加入平面圖
系列文
收納規劃APP32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言